#ifndef __COMM_H__
#define __COMM_H__

#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <math.h>


#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief common error code definition
*/
#define SUCC (0)
#define FAIL (-1)


/**
 * @brief bool constants
*/
#ifndef TRUE
    #define TRUE  (1L)
#endif

#ifndef FALSE
    #define FALSE (0L)
#endif

/**
 * @brief useful macro definition
*/
#ifndef MAX
    #define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif

#ifndef MIN
    #define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif

#ifndef ARRAY_SIZE
    #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
#endif

#ifndef BIT_SET
#define BIT_SET(num, bit)       ((num) |= (1ULL << (bit)))
#endif // BIT_SET


#ifndef BIT_RESET
#define BIT_RESET(num, bit)     ((num) &=(~(1ULL << (bit))))
#endif // BIT_RESET

#ifndef BIT_GET
#define BIT_GET(num, bit)       (((num) & (1ULL << (bit))) > 0 ? 1 : 0)
#endif // BIT_GET

#ifndef BITS_SET
#define BITS_SET(num,bit_start,bit_num)         \
do {                                            \
    for(uint8_t i = 0; i <(bit_num); i++) {     \
        BIT_SET(num,bit_start+i);               \
    }                                           \
}while(0)
#endif

#ifndef BITS_RESET
#define BITS_RESET(num,bit_start,bit_num)       \
do {                                            \
    for(uint8_t i = 0; i <(bit_num); i++) {     \
        BIT_RESET(num,(bit_start)+i);           \
    }                                           \
}while(0)
#endif

#ifndef BITS_GET
#define BITS_GET(num,bit_start,bit_num)         \
do {                                            \
    uint32_t rval = 0;                          \
    uint32_t sval = 0;                          \
	  BITS_SET(sval,bit_start,bit_num);         \
    (num)&sval;                                 \
}while(0)
#endif

#ifndef ENDIAN_SWAP_16
#define ENDIAN_SWAP_16(num)			(((num & 0x00ff) << 8) | ((num & 0xff00) >> 8))
#endif

#ifndef ENDIAN_SWAP_32
#define ENDIAN_SWAP_32(num)			(((num & 0x000000ff) << 24) + ((num & 0x0000ff00) << 8) + ((num & 0x00ff0000) >> 8) + ((num & 0xff000000) >> 24))
#endif

#ifndef CLK_K
#define CLK_K(x) ((double)(x)*1000.0L)
#endif

#ifndef CLK_M
#define CLK_M(x) (CLK_K(x)*1000000.0L)
#endif

#ifndef SZ_K
#define SZ_K(x) ((x)*1024ULL)
#endif

#ifndef SZ_M
#define SZ_M(x) ((SZ_K(x)*1024ULL))
#endif

// #ifndef ALIGN
// #define ALIGN(len,align_n) ((len+align_n-1)&(align_n-1))
// #endif

/* 
return:
    if d1>d2,return 1
    if d1==d2,return 0
    if d1<d2,return -1
 */
#define D_EPSLION (1e-8)
static inline int32_t cmp_double(double d1, double d2)
{
    if (d1 - d2 > D_EPSLION) {
        return 1;
    } else if (d2 - d1 > D_EPSLION) //(abs(d1-d2)<D_EPSLION)
    {
        return -1;
    }
    return 0;
}



/* 
return:
    if d1>d2,return 1
    if d1==d2,return 0
    if d1<d2,return -1
 */
#define F_EPSLION (1e-6)
static inline int32_t cmp_float(float d1, float d2)
{
    if (d1 - d2 > F_EPSLION) {
        return 1;
    } else if (d2 - d1 > F_EPSLION) //(abs(d1-d2)<F_EPSLION)
    {
        return -1;
    }
    return 0;
}


/**
 * @brief compare a with b within the margin of error
 * @param err :the amrgin of error
 * @return : -1 : b > a + err
 *          0 :  -err <=(a - b)<= err
 *          1 : a > b + err
  */
static inline  int32_t cmp_err(float a,float b, float err)
{
    double sub = a - b;
    if (cmp_float(fabs(sub),err)<=0) {
        return 0;
    } else if (cmp_float(sub, err) > 0) { /* a-b > err*/
        return 1;
    } else { /* a-b < -err */
        return -1;
    }
}


#ifdef __cplusplus
}
#endif

#endif // __COMM_H__
